using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.Diagnostics;
using Microsoft.Xna.Framework.Input.Touch;

namespace Services
{
	public interface IInputManager
	{
		event InputManager.TouchEvent OnTouch;
		event InputManager.TouchEvent OnTap;
		event InputManager.TouchEvent OnDoubleTap;
		event InputManager.TouchEvent OnMove;
		event InputManager.PhoneButtonEvent OnBack;

		event InputManager.KeyboardEvent OnKeyDown;
		event InputManager.KeyboardEvent OnKeyUp;

		Boolean IsTouchEnabled
		{
			get; set;
		}
	}

	public class InputManager : GameComponent, IInputManager
	{
		public delegate void TouchEvent(Vector2 touchPosition);
		public event TouchEvent OnTouch;
		public event TouchEvent OnTap;
		public event TouchEvent OnMove;
		public event TouchEvent OnDoubleTap;

		public delegate void PhoneButtonEvent();
		public event PhoneButtonEvent OnBack;

		public delegate void KeyboardEvent(Keys key);
		public event KeyboardEvent OnKeyDown;
		public event KeyboardEvent OnKeyUp;

		private KeyboardState oldKeyboardState;
		private MouseState oldMouseState;

		private Vector2 lastDragPos;

		public Boolean IsTouchEnabled { get; set; }

		public InputManager(Game game)
			: base(game)
		{
			IsTouchEnabled = true;
		}

		public override void Initialize()
		{
			Game.Services.AddService(typeof(IInputManager), this);
			TouchPanel.EnabledGestures =
						GestureType.Tap |
						//GestureType.DoubleTap |
						GestureType.FreeDrag |
						GestureType.DragComplete;

			lastDragPos = new Vector2();

			base.Initialize();
		}

		protected override void Dispose(bool disposing)
		{
			Game.Services.RemoveService(typeof(IInputManager));
			base.Dispose(disposing);
		}

		public override void Update(GameTime gameTime)
		{
			HandleTouches(gameTime);
			HandleKeyboard(gameTime);

			if (GamePad.GetState(PlayerIndex.One).IsButtonDown(Buttons.Back))
			{
				if (OnBack != null) OnBack();
			}

			base.Update(gameTime);
		}

		private void HandleTouches(GameTime gameTime)
		{
			if (!IsTouchEnabled) return;

			MouseState mouseState = Mouse.GetState();
			Vector2 mousePosition = new Vector2(mouseState.X, mouseState.Y);

			if (mouseState.LeftButton == ButtonState.Pressed)
			{
				if (oldMouseState.LeftButton == ButtonState.Released)
				{
					if (OnTouch != null) OnTouch(mousePosition);
				}
			}

#if WINDOWS
			if (mouseState.LeftButton == ButtonState.Released &&
				oldMouseState.LeftButton == ButtonState.Pressed)
			{
				if (OnTap != null) OnTap(mousePosition);
			}
#endif

			oldMouseState = mouseState;

			while (TouchPanel.IsGestureAvailable)
			{
				GestureSample gesture = TouchPanel.ReadGesture();

				switch (gesture.GestureType)
				{
					case GestureType.Tap:
						if (OnTap != null) OnTap(gesture.Position);
						break;

					case GestureType.DoubleTap:
						if (OnDoubleTap != null) OnDoubleTap(gesture.Position);
						break;

					case GestureType.FreeDrag:
						lastDragPos = gesture.Position;
						if (OnMove != null) OnMove(gesture.Position);
						break;

					case GestureType.DragComplete:
						if (OnTap != null) OnTap(lastDragPos);
						break;

					default:
						break;
				}
			}
		}

		private void HandleKeyboard(GameTime gameTime)
		{
			KeyboardState keyboardState = Keyboard.GetState();
			Keys[] pressedKeys = keyboardState.GetPressedKeys();

			foreach (Keys key in pressedKeys)
			{
				if (oldKeyboardState.IsKeyUp(key))
					if (OnKeyDown != null) OnKeyDown(key);
			}

			Keys[] oldPressedKeys = oldKeyboardState.GetPressedKeys();
			foreach (Keys key in oldPressedKeys)
			{
				if (keyboardState.IsKeyUp(key))
					if (OnKeyUp != null) OnKeyUp(key);
			}

			oldKeyboardState = keyboardState;
		}
	}
}
